/*
 * rational.cc
 *
 *  Created on: Sep 26, 2012
 *      Author: shaohong
 */

#include "rational.hh"
#include <iostream>
using namespace std;

Rational::Rational(int numerator, int denominator) {
	this->numerator = numerator;
	this->denominator = denominator;

	normalize();
}

int Rational::getNumerator() const {
	return numerator;
}

int Rational::getDenominator() const {
	return denominator;
}

Rational::Rational(int num) {
	this->numerator = num;
	this->denominator = 1;

	normalize();
}

Rational::Rational(const Rational& rhs) {
	this->numerator = rhs.numerator;
	this->denominator = rhs.denominator;
}

// normalize the numerator and denominator
void Rational::normalize(){

	if (numerator == 0) {
		denominator = 1;
		return;
	}

	// make the denominator always positive
	if (denominator < 0) {
		denominator = -denominator;
		numerator = -numerator;
	}

	int sign=1;
	if (numerator < 0) {
		sign = -1;
		numerator = -numerator;
	}

	int divisor = gcd(numerator, denominator);
	numerator = numerator / divisor * sign;
	denominator = denominator / divisor;
}

std::ostream& operator<< (std::ostream& out, const Rational& rational) {
//	   The output stream operators "normalize" the rational number.
//	   For example, 2/4 is written to output as "1 2",
//	   1/-2 is written to output as "-1 2" and -2/-4 is written as
//	   "1 2".

	if (0 == rational.numerator) {
		out << "0";
	} else {
		out << rational.numerator << " " << rational.denominator;
	}


	return out;
}

std::istream& operator>> (std::istream& in, Rational& rational) {
	int newNumerator;
	int newDenominator;

	in >> newNumerator;
	if (!in.fail()) {
		if (! in.eof()) {
			in >> newDenominator;
			if (! in.fail()) {
				rational.numerator = newNumerator;
				rational.denominator = newDenominator;
			}
		} else {
			rational.numerator = newNumerator;
			rational.denominator = 1;
		}
	}

	return in;
}


Rational & Rational::operator+=(const Rational & rhs) {

	int newDenominator = this->denominator * rhs.denominator;
	int newNumerator = this->numerator * rhs.denominator + rhs.numerator * this->denominator;

	denominator = newDenominator;
	numerator = newNumerator;
	normalize();

	return *this;
}

Rational & Rational::operator-=(const Rational & rhs) {
	int newDenominator = this->denominator * rhs.denominator;
	int newNumerator = this->numerator * rhs.denominator - rhs.numerator * this->denominator;

	denominator = newDenominator;
	numerator = newNumerator;
	normalize();

	return *this;
}

bool operator<(const Rational& lhs, const Rational & rhs){
	Rational diff = lhs - rhs;

	return (diff.getNumerator() < 0);

}

bool operator>(const Rational& lhs, const Rational & rhs){
	Rational diff = lhs - rhs;

	return (diff.getNumerator() > 0);

}

bool operator<=(const Rational& lhs, const Rational & rhs) {
	return ! (lhs > rhs);
}

bool operator==(const Rational& lhs, const Rational & rhs) {
	int newNumerator = lhs.numerator*rhs.denominator - lhs.denominator * rhs.numerator;

	if (newNumerator == 0) {
		return true;
	} else {
		return false;
	}
}

bool operator>=(const Rational& lhs, const Rational & rhs) {
	return ! (lhs < rhs);
}

bool operator!=(const Rational& lhs, const Rational & rhs) {
	return ! (lhs == rhs);
}

Rational operator+(const Rational& lhs, const Rational& rhs) {
	int newDenominator = lhs.denominator * rhs.denominator;
	int newNumerator = lhs.numerator * rhs.denominator + rhs.numerator * lhs.denominator;

	return Rational(newNumerator, newDenominator);

}

Rational operator+(int num,const Rational& rhs) {
	Rational lhs(num);
	return lhs+rhs;
}

Rational operator-(const Rational& lhs, const Rational& rhs) {
	int newNumerator = lhs.numerator*rhs.denominator - lhs.denominator * rhs.numerator;
	int newDenominator = lhs.denominator * rhs.denominator;

	Rational result(newNumerator, newDenominator);
	return result;
}

Rational operator-(int num,const Rational& rhs) {
	Rational lhs(num);
	return lhs-rhs;
}

// Unary operator -
Rational Rational::operator-(){
	return Rational(this->getNumerator(), -1*this->getDenominator());
}
